﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Web.Http.OData.Query;

using Inovout.Cloud.DataStore.Common;
using Inovout.Cloud.DataStore.Models;
using Inovout.Cloud.DataStore.Utility;
using Inovout.Runtime;
using Inovout.Services;
using Inovout.Models;
using MongoDB.Bson;

namespace Inovout.Cloud.DataStore.Services
{
    public class EntityService : RepositoryService<Entity>, IEntityService
    {
        private MongoDbClient mongoDbClient;
        public MongoDbClient MongoDbClient
        {
            get
            {
                if (mongoDbClient == null)
                {
                    mongoDbClient = new MongoDbClient(ComponentRegistry.Resolve<IApplication>().Settings["MongoDbConnectionString"].ToString());
                }

                return mongoDbClient;
            }
        }

        /// <summary>
        /// 查询表的记录数
        /// </summary>
        /// <param name="databaseName">数据库名</param>
        /// <param name="tableName">表名</param>
        /// <returns>记录数</returns>
        public int GetEntityCount(string databaseName, string tableName)
        {
            if (!ValidateTable(databaseName, tableName))
            {
                return 0;
            }

            return this.MongoDbClient.GetEntityCount(databaseName, tableName);
        }

        /// <summary>
        /// 查询所有的记录
        /// </summary>
        /// <param name="databaseName">数据库名</param>
        /// <param name="tableName">表名</param>
        /// <returns>所有记录</returns>
        public IQueryable QueryAll(string databaseName, string tableName)
        {
            if (!ValidateTable(databaseName, tableName))
            {
                return null;
            }

            IDatabaseService databaseService = ComponentRegistry.Resolve<IDatabaseService>();
            Database database = databaseService.FindByName(databaseName);
            if (database == null)
            {
                return null;
            }

            ITableService tableService = ComponentRegistry.Resolve<ITableService>();
            Table table = tableService.FindByName(database, tableName);

            if (table == null)
            {
                return null;
            }

            if (table.Properties == null || table.Properties.Count == 0)
            {
                return null;
            }

            string nameSpace = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Namespace;
            Type tableType = table.GetClrType(typeof(Models.MongoProperty), nameSpace);

            return this.MongoDbClient.FindAllEntities(databaseName, tableName, tableType);
        }

        /// <summary>
        /// 根据ObjectId查询记录
        /// </summary>
        /// <param name="databaseName">数据库名</param>
        /// <param name="tableName">表名</param>
        /// <returns>符合条件的记录</returns>
        public BsonDocument FindOneByObjectId(string databaseName, string tableName, string primaryKey)
        {
            if (!ValidateTable(databaseName, tableName))
            {
                return null;
            }

            IDatabaseService databaseService = ComponentRegistry.Resolve<IDatabaseService>();
            Database database = databaseService.FindByName(databaseName);
            if (database == null)
            {
                return null;
            }

            ITableService tableService = ComponentRegistry.Resolve<ITableService>();
            Table table = tableService.FindByName(database, tableName);

            if (table == null)
            {
                return null;
            }

            return this.MongoDbClient.FindOneByObjectId(databaseName, tableName, primaryKey);
        }
        /// <summary>
        /// 插入记录
        /// </summary>
        /// <param name="databaseName">数据库名</param>
        /// <param name="tableName">表名</param>
        /// <param name="entity">记录（格式：name-value）</param>
        public void InsertEntity(string databaseName, string tableName, Dictionary<string, object> entity)
        {
            if (!ValidateTable(databaseName, tableName))
            {
                return;
            }

            if (entity == null || entity.Count == 0)
            {
                return;
            }

            Iesi.Collections.Generic.ISet<Property> tableProperties = getTableProperties(databaseName, tableName);
            if (tableProperties == null || tableProperties.Count == 0)
            {
                return;
            }

            //MongoDB的主键"_id"的值=插入数据的主键的值，多个主键用“,”隔开
            string primaryKeyValue = getPrimaryKeyValue(tableProperties, entity);

            if (!String.IsNullOrEmpty(primaryKeyValue))
            {
                if (!entity.ContainsKey(Constant.ObjectId))
                {
                    entity.Add(Constant.ObjectId, primaryKeyValue);
                }
            }

            this.MongoDbClient.InsertEntity(databaseName, tableName, entity);
        }

        /// <summary>
        /// 批量插入记录
        /// </summary>
        /// <param name="databaseName">数据库名</param>
        /// <param name="tableName">表名</param>
        /// <param name="entities">记录集合</param>
        public void InsertEntitiesBatch(string databaseName, string tableName, List<Dictionary<string, object>> entities)
        {
            if (!ValidateTable(databaseName, tableName))
            {
                return;
            }

            if (entities == null || entities.Count == 0)
            {
                return;
            }

            Iesi.Collections.Generic.ISet<Property> tableProperties = getTableProperties(databaseName, tableName);
            if (tableProperties == null || tableProperties.Count == 0)
            {
                return;
            }

            string primaryKeyValue = null;
            foreach (Dictionary<string, object> entity in entities)
            {
                //MongoDB的主键"_id"的值=插入数据的主键的值，多个主键用“,”隔开
                primaryKeyValue = getPrimaryKeyValue(tableProperties, entity);
                if (!String.IsNullOrEmpty(primaryKeyValue))
                {
                    if (!entity.ContainsKey(Constant.ObjectId))
                    {
                        entity.Add(Constant.ObjectId, primaryKeyValue);
                    }
                }
            }

            this.MongoDbClient.InsertEntitiesBatch(databaseName, tableName, entities);
        }

        /// <summary>
        /// 更新记录
        /// </summary>
        /// <param name="databaseName">数据库名</param>
        /// <param name="tableName">表名</param>
        /// <param name="entity">更新后的对象结果</param>
        public void UpdateEntity(string databaseName, string tableName, Dictionary<string, object> entity)
        {
            if (!ValidateTable(databaseName, tableName))
            {
                return;
            }

            if (entity == null || entity.Count == 0)
            {
                return;
            }

            Iesi.Collections.Generic.ISet<Property> tableProperties = getTableProperties(databaseName, tableName);
            if (tableProperties == null || tableProperties.Count == 0)
            {
                return;
            }

            //MongoDB的主键"_id"的值=插入数据的主键的值，多个主键用“,”隔开
            string primaryKeyValue = getPrimaryKeyValue(tableProperties, entity);
            if (String.IsNullOrEmpty(primaryKeyValue))
            {
                return;
            }

            this.MongoDbClient.UpdateEntity(databaseName, tableName, primaryKeyValue, entity);
        }

        /// <summary>
        /// 更新记录
        /// </summary>
        /// <param name="databaseName">数据库名</param>
        /// <param name="tableName">表名</param>
        /// <param name="primaryKey">被更新记录的主键</param>
        /// <param name="entity">更新后的对象结果</param>
        public void UpdateEntity(string databaseName, string tableName, string primaryKey, Dictionary<string, object> entity)
        {
            if (!ValidateTable(databaseName, tableName) || String.IsNullOrEmpty(primaryKey))
            {
                return;
            }

            Iesi.Collections.Generic.ISet<Property> tableProperties = getTableProperties(databaseName, tableName);
            if (tableProperties == null || tableProperties.Count == 0)
            {
                return;
            }

            this.MongoDbClient.UpdateEntity(databaseName, tableName, primaryKey, entity);
        }

        /// <summary>
        /// Save方法是Insert和Update方法的组合。
        /// 如果ID字段有值则假定该文档是存在的并保存所有更新，否则插入一条新的文档记录。
        /// </summary>
        /// <param name="databaseName">数据库名</param>
        /// <param name="tableName">表名</param>
        /// <param name="primaryKey">主键</param>
        /// <param name="entity">记录结果</param>
        public void SaveEntity(string databaseName, string tableName, Dictionary<string, object> entity)
        {
            if (!ValidateTable(databaseName, tableName) || entity == null || entity.Count == 0)
            {
                return;
            }

            Iesi.Collections.Generic.ISet<Property> tableProperties = getTableProperties(databaseName, tableName);
            if (tableProperties == null || tableProperties.Count == 0)
            {
                return;
            }

            //MongoDB的主键"_id"的值=插入数据的主键的值，多个主键用“,”隔开
            string primaryKeyValue = getPrimaryKeyValue(tableProperties, entity);
            if (!String.IsNullOrEmpty(primaryKeyValue))
            {
                if (!entity.ContainsKey(Constant.ObjectId))
                {
                    entity.Add(Constant.ObjectId, primaryKeyValue);
                }
            }

            this.MongoDbClient.SaveEntity(databaseName, tableName, entity);
        }

        /// <summary>
        /// 批量保存记录集
        /// </summary>
        /// <param name="databaseName"></param>
        /// <param name="tableName"></param>
        /// <param name="entities"></param>
        public void SaveEntities(string databaseName, string tableName, List<Dictionary<string, object>> entities)
        {
            if (!ValidateTable(databaseName, tableName) || entities == null || entities.Count == 0)
            {
                return;
            }

            Iesi.Collections.Generic.ISet<Property> tableProperties = getTableProperties(databaseName, tableName);
            if (tableProperties == null || tableProperties.Count == 0)
            {
                return;
            }

            string primaryKeyValue = null;
            foreach (Dictionary<string, object> entity in entities)
            {
                //MongoDB的主键"_id"的值=插入数据的主键的值，多个主键用“,”隔开
                primaryKeyValue = getPrimaryKeyValue(tableProperties, entity);
                if (!String.IsNullOrEmpty(primaryKeyValue))
                {
                    if (!entity.ContainsKey(Constant.ObjectId))
                    {
                        entity.Add(Constant.ObjectId, primaryKeyValue);
                    }
                }
            }

            this.MongoDbClient.SaveEntities(databaseName, tableName, entities);
        }

        /// <summary>
        /// 删除记录
        /// </summary>
        /// <param name="databaseName">数据库名</param>
        /// <param name="tableName">表名</param>
        /// <param name="primaryKey">主键</param>
        public void DeleteEntity(string databaseName, string tableName, string primaryKey)
        {
            if (!ValidateTable(databaseName, tableName))
            {
                return;
            }

            this.MongoDbClient.RemoveEntity(databaseName, tableName, primaryKey);
        }

        /// <summary>
        /// 根据条件删除记录
        /// </summary>
        /// <param name="databaseName">数据库名</param>
        /// <param name="tableName">表名</param>
        /// <param name="condition">条件</param>
        public void DeleteEntity(string databaseName, string tableName, Dictionary<string, object> condition)
        {
            if (!ValidateTable(databaseName, tableName) || condition == null || condition.Count == 0)
            {
                return;
            }

            Iesi.Collections.Generic.ISet<Property> tableProperties = getTableProperties(databaseName, tableName);
            if (tableProperties == null || tableProperties.Count == 0)
            {
                return;
            }

            //MongoDB的主键"_id"的值=插入数据的主键的值，多个主键用“,”隔开
            string primaryKeyValue = getPrimaryKeyValue(tableProperties, condition);

            if (!String.IsNullOrEmpty(primaryKeyValue))
            {
                this.MongoDbClient.RemoveEntity(databaseName, tableName, primaryKeyValue);
                return;
            }

            this.MongoDbClient.RemoveEntities(databaseName, tableName, condition);
        }

        /// <summary>
        /// 清空表
        /// </summary>
        /// <param name="databaseName">数据库名</param>
        /// <param name="tableName">表名</param>
        public void DeleteAllEntities(string databaseName, string tableName)
        {
            if (!ValidateTable(databaseName, tableName))
            {
                return;
            }

            this.MongoDbClient.RemoveAllEntities(databaseName, tableName);
        }

        private bool ValidateTable(string databaseName, string tableName)
        {
            if (String.IsNullOrEmpty(databaseName) || String.IsNullOrEmpty(tableName))
            {
                return false;
            }

            return true;
        }

        private bool ValidateTable(Table table)
        {
            if (table == null || table.Database == null ||
                String.IsNullOrEmpty(table.Database.Name) || String.IsNullOrEmpty(table.Name))
            {
                return false;
            }

            return true;
        }

        private Iesi.Collections.Generic.ISet<Property> getTableProperties(string databaseName, string tableName)
        {
            IDatabaseService databaseService = ComponentRegistry.Resolve<IDatabaseService>();
            Database database = databaseService.FindByName(databaseName);
            if (database == null)
            {
                return null;
            }

            ITableService tableService = ComponentRegistry.Resolve<ITableService>();
            Table table = tableService.FindByName(database, tableName);
            if (table == null)
            {
                return null;
            }

            if (table.Properties == null || table.Properties.Count == 0)
            {
                return null;
            }

            return table.Properties;
        }

        private string getPrimaryKeyValue(Iesi.Collections.Generic.ISet<Property> properties, Dictionary<string, object> entity)
        {
            if (properties == null || properties.Count == 0)
            {
                return null;
            }

            if (entity == null || entity.Count == 0)
            {
                return null;
            }

            string primaryKeyValue = "";
            foreach (Property property in properties)
            {
                if (property.IsPrimaryKey)
                {
                    if (entity.ContainsKey(property.Name))
                    {
                        primaryKeyValue = primaryKeyValue + "," + entity[property.Name].ToString();
                    }
                }
            }

            if (primaryKeyValue != "")
            {
                primaryKeyValue = primaryKeyValue.Substring(1);

                return primaryKeyValue;
            }
            else
            {
                return null;
            }
        }
    }
}
